#pragma once
#include <math.h>

namespace FourthEngineMath{

	class Vector2{
	private:
		float pad_1, pad_2;
	public:
		float x, y;

		Vector2(){
			pad_1 = pad_2 = 0.0f;
			x = y = 0.0f;
		};
		~Vector2(){};

		Vector2(float a_x, float a_y){
			x = a_x;
			y = a_y;
		};

		void add(Vector2 a_Vector2){
			x += a_Vector2.x;
			y += a_Vector2.y;
		};

		Vector2 plus(Vector2 a_Vector2){
			Vector2 temp_Vector2;
			temp_Vector2.x += a_Vector2.x;
			temp_Vector2.y += a_Vector2.y;
			return temp_Vector2;
		};

		void subtract(Vector2 a_Vector2){
			x -= a_Vector2.x;
			y -= a_Vector2.y;
		};

		Vector2 minus(Vector2 a_Vector2){
			Vector2 temp_Vector2;
			temp_Vector2.x -= a_Vector2.x;
			temp_Vector2.y -= a_Vector2.y;
			return temp_Vector2;
		};

		void multiply(float a_float){
			x *= a_float;
			y *= a_float;
		};

		Vector2 times(float a_float){
			Vector2 temp_Vector2;
			temp_Vector2.x *= a_float;
			temp_Vector2.y *= a_float;
			return temp_Vector2;
		};

		float magnitude(){
			return sqrt(x*x+y*y);
		};

		float magnitudeSquare(){
			return (x*x+y*y);
		};

		Vector2 normal(){
			Vector2 normal(0.0f, 0.0f);
			float length = magnitude();
			if(length > 0.0f){
				normal.x /= length;
				normal.y /= length;
			}
			return normal;
		};

		void normalize(){
			float length = magnitude();
			if(length > 0.0f){
				x /= length;
				y /= length;
			}
		};

		void componentProduct(Vector2 a_Vector2){
			x *= a_Vector2.x;
			y *= a_Vector2.y;
		};

		Vector2 componentProductVec(Vector2 a_Vector2){
			return Vector2(x * a_Vector2.x, y * a_Vector2.y);
		};

		float dotProduct(Vector2 a_Vector2){
			return (x * a_Vector2.x + y * a_Vector2.y);
		};

		Vector2 orthogonal(){
			Vector2 temp_Vector2;
			temp_Vector2.x = -y;
			temp_Vector2.y = x;
			return temp_Vector2;
		};

		void invert(){
			x = -x;
			y = -y;
		};
	};

	class Vector3{
	private:
		float pad;
	public:
		float x, y, z;

		Vector3(){
			pad = 0.0f;
			x = y = z = 0.0f;
		};
		~Vector3(){};

		Vector3(float a_x, float a_y, float a_z){
			x = a_x;
			y = a_y;
			z = a_z;
		};

		void add(Vector3 a_Vector3){
			x += a_Vector3.x;
			y += a_Vector3.y;
			z += a_Vector3.z;
		};

		Vector3 plus(Vector3 a_Vector3){
			Vector3 temp_Vector3;
			temp_Vector3.x += a_Vector3.x;
			temp_Vector3.y += a_Vector3.y;
			temp_Vector3.z += a_Vector3.z;
			return temp_Vector3;
		};

		void subtract(Vector3 a_Vector3){
			x -= a_Vector3.x;
			y -= a_Vector3.y;
			z -= a_Vector3.z;
		};

		Vector3 minus(Vector3 a_Vector3){
			Vector3 temp_Vector3;
			temp_Vector3.x = x - a_Vector3.x;
			temp_Vector3.y = y - a_Vector3.y;
			temp_Vector3.z = z - a_Vector3.z;
			return temp_Vector3;
		};

		void multiply(float a_float){
			x *= a_float;
			y *= a_float;
			z *= a_float;
		};

		Vector3 times(float a_float){
			Vector3 temp_Vector3;
			temp_Vector3.x = x * a_float;
			temp_Vector3.y = y * a_float;
			temp_Vector3.z = z * a_float;
			return temp_Vector3;
		};

		void equal(Vector3 a_Vector3){
			x = a_Vector3.x;
			y = a_Vector3.y;
			z = a_Vector3.z;
		};

		float distance3D(Vector3 a_Vector3){
			float dX, dY, dZ;
			dX = dY = dZ = 0;
			dX = (a_Vector3.x-x);
			dY = (a_Vector3.y-y);
			dZ = (a_Vector3.z-z);
			return sqrt((dX*dX)+(dY*dY)+(dZ*dZ));
		};

		Vector3 midpoint(Vector3 a_Vector3){
			Vector3 temp_Midpoint;
			temp_Midpoint.x = (x+a_Vector3.x)/2;
			temp_Midpoint.y = (y+a_Vector3.y)/2;
			temp_Midpoint.z = (z+a_Vector3.z)/2;
			return temp_Midpoint;
		};

		float magnitude(){
			return sqrt(x*x+y*y+z*z);
		};

		float magnitudeSquare(){
			return (x*x+y*y+z*z);
		};

		Vector3 normal(){
			Vector3 normal(x, y, z);
			float length = magnitude();
			if(length > 0.0f){
				normal.x /= length;
				normal.y /= length;
				normal.z /= length;
			}
			return normal;
		};

		void normalize(){
			float length = magnitude();
			if(length > 0.0f){
				x /= length;
				y /= length;
				z /= length;
			}
		};

		void componentProduct(Vector3 a_Vector3){
			x *= a_Vector3.x;
			y *= a_Vector3.y;
			y *= a_Vector3.z;
		};

		Vector3 componentProductVec(Vector3 a_Vector3){
			return Vector3(x * a_Vector3.x, y * a_Vector3.y, z * a_Vector3.z);
		};

		float dotProduct(Vector3 a_Vector3){
			return (x * a_Vector3.x + y * a_Vector3.y + z * a_Vector3.z);
		};

		Vector3 crossProduct(Vector3 a_Vector3){
			Vector3 temp_Vector3;
			temp_Vector3.x = y * a_Vector3.z - a_Vector3.y * z;
			temp_Vector3.y = z * a_Vector3.x - a_Vector3.z * x;
			temp_Vector3.z = x * a_Vector3.y - a_Vector3.x * y;
			return temp_Vector3;
		};

		void invert(){
			x = -x;
			y = -y;
			z = -z;
		};
	};

};